package com.wei.czz.framework.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.blog.SpaceDto;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.utils.RandomNumUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.framework.common.handler.redis.RedisStringHandler;
import com.wei.czz.common.vo.blog.space.SpaceVo;
import com.wei.czz.common.vo.blog.space.SpaceFormVo;
import com.wei.czz.framework.blog.dao.SpaceDao;
import com.wei.czz.framework.blog.entity.SpaceEntity;
import com.wei.czz.framework.blog.service.SpaceService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-03-15 10:29:48
 * className: SpaceServiceImpl 用户博客空间操作请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("spaceService")
@AllArgsConstructor
public class SpaceServiceImpl extends ServiceImpl<SpaceDao, SpaceEntity> implements SpaceService {

    private static final Logger log = LoggerFactory.getLogger(SpaceServiceImpl.class);

    private final RedisHashHandler redisHashHandler;

    private final RedisStringHandler redisStringHandler;

    private final RedisHandler redisHandler;

    @Override
    public void saveSpace(SpaceVo spaceVo) {
        // 获取正在保存自己空间信息的用户id
        Long optUserId = SecurityUtils.getUserId();

        LambdaQueryWrapper<SpaceEntity> spaceLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 用户id和空间名称 字段
        spaceLambdaWrapper.eq(SpaceEntity::getUserId, optUserId)
                .eq(SpaceEntity::getName, spaceVo.getName());
        // 查询数据库用户博客空间表，统计新空间名称的出现次数
        long count = this.count(spaceLambdaWrapper);
        if (count > 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您已存在该空间名称，请确认后重新操作!");
        }

        Date date = new Date();

        SpaceEntity space = new SpaceEntity();
        // 设置用户id、空间名称、排序等级、更新时间和创建时间
        space.setUserId(optUserId)
                .setName(spaceVo.getName())
                .setSort(spaceVo.getSort())
                .setUpdateTime(date)
                .setCreateTime(date);
        // 操作数据库用户博客空间表，新增一条用户空间信息
        count = baseMapper.insert(space);
        if (count == 0) {
            throw new CzzException("保存用户空间信息失败，请务必及时处理");
        }

        // 操作Redis缓存，保存用户空间信息缓存
        redisHashHandler.put(optUserId + RedisConstant.SPLIT + RedisConstant.SPACE_MAP,
                String.valueOf(space.getSpaceId()), space);
        // 删除该用户所有的空间信息临时缓存
        this.deleteSpaceCache(optUserId);
    }

    @Override
    public List<SpaceEntity> getSpaceList(Long userId) {
        LambdaQueryWrapper<SpaceEntity> spaceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配
        spaceLambdaQueryWrapper.eq(Objects.nonNull(userId), SpaceEntity::getUserId, userId);
        // 查询
        List<SpaceEntity> spaceList = baseMapper.selectList(spaceLambdaQueryWrapper);
        if (spaceList.isEmpty()) {
            log.info("查询用户博客空间结果为空。userId={}", userId);
        }
        return spaceList;
    }

    @Override
    public PageDto<SpaceDto> getSpacePageList(SpaceFormVo spaceFormVo) {
        // 获取正在执行空间列表获取的用户id
        Long optUserId = SecurityUtils.getUserId();

        String userSpaceListKey = optUserId + RedisConstant.SPLIT + spaceFormVo.getSpaceListKey();
        // 查询Redis，获取用户自己的空间信息表
        PageDto<SpaceDto> pageDto = redisStringHandler.get(userSpaceListKey);
        if (pageDto != null) {
            // 尝试更新用户自己的空间列表缓存过期时间
            redisHandler.tryUpdateKeyExpire(userSpaceListKey, 150, RandomNumUtils.random5Minutes(10));
            return pageDto;
        }

        LambdaQueryWrapper<SpaceEntity> spaceLambdaWrapper = new LambdaQueryWrapper<>();
        // 查询 空间id、空间名称、排序等级和创建时间 字段
        spaceLambdaWrapper.select(SpaceEntity::getSpaceId, SpaceEntity::getName, SpaceEntity::getSort,
                        SpaceEntity::getCreateTime);
        // 匹配 用户id 且 模糊查询空间名称 字段
        spaceLambdaWrapper.eq(SpaceEntity::getUserId, optUserId)
                .like(StringUtils.isNotEmpty(spaceFormVo.getWord()), SpaceEntity::getName, spaceFormVo.getWord());
        // 构造mp分页对象
        Page<SpaceEntity> page = PageQuery.initPage(spaceFormVo);

        // 查询数据库用户博客空间表，分页查询用户空间信息列表
        IPage<SpaceEntity> spacePage = this.page(page, spaceLambdaWrapper);
        List<SpaceEntity> spaceList = spacePage.getRecords();

        List<SpaceDto> spaceDtoList = new ArrayList<>(spaceList.size());
        for (SpaceEntity space : spaceList) {
            SpaceDto spaceDto = new SpaceDto();
            // 设置空间id、空间名称、排序等级和创建时间属性值
            spaceDto.setSpaceId(space.getSpaceId().toString())
                    .setName(space.getName())
                    .setSort(space.getSort())
                    .setCreateTime(space.getCreateTime());
            spaceDtoList.add(spaceDto);
        }
        // 返回结果封装
        pageDto = new PageDto<>(spaceDtoList, spacePage.getTotal(), spaceFormVo.getPage(), spaceFormVo.getLimit());
        // 缓存用户空间列表五分钟
        redisStringHandler.set(userSpaceListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

        return pageDto;
    }

    @Override
    public SpaceDto getSpaceInfo(String spaceId) {
        // 获取正在获取自己空间信息的用户id
        Long optUserId = SecurityUtils.getUserId();
        // 查询Redis缓存，获取用户空间信息
        SpaceEntity space = redisHashHandler.get(optUserId + RedisConstant.SPLIT + RedisConstant.SPACE_MAP, spaceId);
        if (space == null) {
            LambdaQueryWrapper<SpaceEntity> spaceLambdaWrapper = new LambdaQueryWrapper<>();
            // 查询 空间名称和排序等级 字段
            spaceLambdaWrapper.select(SpaceEntity::getName, SpaceEntity::getSort);
            // 匹配 空间id 字段
            spaceLambdaWrapper.eq(SpaceEntity::getSpaceId, spaceId);
            // 查询数据库用户博客空间表，查询用户空间信息
            List<SpaceEntity> spaceList = baseMapper.selectList(spaceLambdaWrapper);
            if (spaceList.isEmpty()) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您查询的用户空间不存在，请确认，如有问题，请联系管理员处理。");
            }
            space = spaceList.get(0);
        }
        SpaceDto spaceDto = new SpaceDto();
        // 设置空间名称和排序等级属性值
        spaceDto.setName(space.getName())
                .setSort(space.getSort());
        return spaceDto;
    }

    @Override
    public void updateSpace(SpaceVo spaceVo) {
        // 获取正在获取自己空间信息的用户id
        Long optUserId = SecurityUtils.getUserId();

        long spaceId = Long.parseLong(spaceVo.getSpaceId());

        LambdaQueryWrapper<SpaceEntity> spaceLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 用户id、空间名称和空间id 字段
        spaceLambdaWrapper.eq(SpaceEntity::getUserId, optUserId)
                .eq(SpaceEntity::getName, spaceVo.getName())
                .ne(SpaceEntity::getSpaceId, spaceId);
        // 查询数据库用户博客空间表，统计符合检索条件的数据条数
        long count = this.count(spaceLambdaWrapper);
        if (count > 0) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您已存在该空间名称，请确认后重新操作!");
        }

        SpaceEntity space = new SpaceEntity();
        // 设置空间id、空间名称、排序等级和更新时间属性值
        space.setSpaceId(spaceId)
                .setName(spaceVo.getName())
                .setSort(spaceVo.getSort())
                .setUpdateTime(new Date());
        // 操作数据库用户博客空间表，更新用户空间信息
        count = baseMapper.updateById(space);
        if (count == 0) {
            throw new CzzException("修改用户空间信息失败，请务必及时处理");
        }

        // 获取最新的空间信息
        space = this.getById(spaceVo.getSpaceId());

        // 更新Redis保存的用户空间信息
        redisHashHandler.put(optUserId + RedisConstant.SPLIT + RedisConstant.SPACE_MAP, spaceVo.getSpaceId(), space);
        // 删除该用户所有的空间信息临时缓存
        this.deleteSpaceCache(optUserId);
    }

    @Override
    public void deleteSpace(List<Long> spaceIdList) {
        // 获取正在删除自己空间信息的用户id
        Long optUserId = SecurityUtils.getUserId();

        // 操作数据库用户博客空间表，批量删除用户空间信息
        int count = baseMapper.deleteBatchIds(spaceIdList);
        log.info("删除博客空间完成。count={}", count);

        String[] spaceIds = spaceIdList.stream().map(Object::toString).toArray(String[]::new);
        // 操作Redis缓存，删除的用户空间信息
        redisHashHandler.delete(optUserId + RedisConstant.SPLIT + RedisConstant.SPACE_MAP, spaceIds);
        // 删除该用户所有的空间信息临时缓存
        this.deleteSpaceCache(optUserId);
    }

    /**
     * 删除该用户所有的空间信息临时缓存
     * @param optUserId 用户id
     */
    private void deleteSpaceCache(Long optUserId) {
        String patternKey = optUserId + RedisConstant.SPLIT + RedisConstant.SPACE_LIST + RedisConstant.ASTERISK;
        redisHandler.fuzzyDelete(patternKey);
    }
}